-- 2022-8-15

---[[ 错误信息和栈回溯

    -- 虽然能够使用任何类型的值作为错误对象 但错误对象通常是一个描述出错内容的字符串
    -- 当遇到内部错误(比如尝试对一个非表类型的值进行索引操作)出现时 Lua语言负责产生错误对象(这种情况下的错误对象永远是字符串 而在其他情况下 错误的对象是传递给函数error的值)
    -- 如果错误对象是一个字符串 那么Lua语言还会尝试把一些有关错误发生位置的信息附上
    local status ,err = pcall(function () error("my error") end)
    print(err)  -- stdin:1: my error
    -- 位置信息中给出了出错代码段的名称(上例中的stdin)和行号(上例中的1)
    -- 函数error的第2个可选参数level 用于指出向函数调用层次中的哪层函数报告错误 以说明谁应该为错误负责
    -- 例如 假设编写一个用来检查其自身是否被正确调用了的函数
    function foo (str)
        if type(str) ~= "string" then
            error("string excepted")
        end
        -- regular code
    end
    -- 如果调用时被传递了错误的参数
    foo({x=1})
    -- 由于是函数foo调用的error 所以Lua语言会认为是函数foo发生了错误
    -- 然而 真正的肇事者其实是函数foo的调用者 为了纠正这个错误 我们需要告诉error函数错误实际发生在函数调用层次的第2层中(第1层是foo函数自己)
    function foo (str)
        if type(str)~="string" then
            error("string excepted",2)
        end
        -- regular code
    end

    -- 通常 除了发生错误的位置以外 我们还希望在错误发生时得到更多的调试信息
    -- 至少 我们希望得到具有发生错误时完整函数调用栈的栈回溯(traceback)
    -- 当函数pcall返回错误信息时 部分的调用栈已经被破坏了(从pcall到出错之处的部分)
    -- 因此 如果希望得到一个有意义的栈回溯 那么就必须在函数pcall返回前先将调用栈构造好
    -- 为了完成这个需求 Lua语言提供了函数xpcall 该函数与函数pcall类似 但它的第2个参数是一个消息处理函数(message handler function)
    -- 当发生错误时 Lua会在调用栈展开(stack unwind)前调用这个消息处理函数 以便消息处理函数能够使用调试库来获取有关错误的更多信息
    -- 两个常用的消息处理函数是debug.debug和debug.traceback 前者为用户提供了一个Lua提示符来让用户检查错误发生的原因
    -- 后者则使用调用栈来构造详细的错误信息 Lua语言的独立解释器就是使用这个函数来构造错误信息的
--]]